package jp.co.ricoh.melody.views.adapters;

import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SwitchCompat;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import jp.co.ricoh.melody.R;
import jp.co.ricoh.melody.databases.DBManager;
import jp.co.ricoh.melody.databinding.AlarmItemViewBinding;
import jp.co.ricoh.melody.models.entities.AlarmData;
import jp.co.ricoh.melody.presenters.AlarmListPresenter;
import jp.co.ricoh.melody.presenters.IAlarmListPresenter;
import jp.co.ricoh.melody.utils.CommonUtils;
import jp.co.ricoh.melody.utils.ConstantUtils;
import jp.co.ricoh.melody.views.activities.AddAlarmActivity;
import jp.co.ricoh.melody.views.activities.MainActivity;

/**
 * Copyright (C) 2016 RICOH Co.,LTD.
 * All rights reserved.
 */
public class AlarmListView extends RecyclerView implements IAlarmListView {

    private static final String TAG = AlarmListView.class.getSimpleName();

    private final int OFFSET_VISIBLE_ITEM_COUNT = 1;

    private static final int COLUMN_COUNT = 2;

    private final int FLAG_DRAG = 0;

    private IAlarmListPresenter mPresenter;
    /**
     * A gray view that will visible and fullscreen when drag event started
     */
    private RelativeLayout mRecycleBinContainer;
    /**
     * The recycle bin image
     */
    private ImageView mRecycleBinImg;
    private boolean mIsRecycleBinActive = false;
    private MainActivity mMainActivity;

    public AlarmListView(Context context) {
        super(context);
        init();
    }

    public AlarmListView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AlarmListView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    void init() {
        mPresenter = new AlarmListPresenter();
        mPresenter.onCreateView(this);
        GridLayoutManager layoutManager = new GridLayoutManager(getContext(), COLUMN_COUNT, RecyclerView.VERTICAL, false) {
            @Override
            public boolean canScrollVertically() {
                int visibleCount = findLastCompletelyVisibleItemPosition() - findFirstCompletelyVisibleItemPosition() + OFFSET_VISIBLE_ITEM_COUNT;
                int itemCount = mPresenter.getItemCount();
                return itemCount > visibleCount && super.canScrollVertically();
            }
        };
        setLayoutManager(layoutManager);
        setItemAnimator(new DefaultItemAnimator());
        final int itemMargin = getContext().getResources().getDimensionPixelOffset(R.dimen.dimen_alarm_item_margin);
        addItemDecoration(new ItemDecoration() {
            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
                super.getItemOffsets(outRect, view, parent, state);
                outRect.left = itemMargin;
                outRect.right = itemMargin;
                outRect.top = itemMargin;
            }
        });

        mPresenter.loadData();

    }

    /**
     * Click on melody item
     */
    private OnClickListener mOnItemClickListener = new OnClickListener() {
        @Override
        public void onClick(View view) {
            AlarmItemViewHolder holder = (AlarmItemViewHolder) view.getTag();
            mPresenter.editAlarm(holder.mAlarmData.getId());
        }
    };
    /**
     * Click on switch button
     */
    private OnClickListener mSwitchClickListener = new OnClickListener() {
        @Override
        public void onClick(View view) {
            SwitchCompat switchView = (SwitchCompat) view;
            AlarmItemViewHolder holder = (AlarmItemViewHolder) view.getTag();
            mMainActivity.showProgressDialog(mMainActivity.getString(R.string.progress_dialog_msg_save));
            mPresenter.setEnableAlarm(switchView.isChecked(), holder.mAlarmData, new DBManager.OnSaveDataResultListener() {
                @Override
                public void onSuccess() {
                    mMainActivity.dismissProgressDialog();
                }

                @Override
                public void onError(int i) {
                    mMainActivity.dismissProgressDialog();
                    CommonUtils.showHDDErrorDialog(mMainActivity, i);
                }
            });
        }
    };
    /**
     * By default, user need to drag switch button to change it's state.
     * It's not easy for them, we want to one click to change it's state.
     * So we prevent drag event on it and handle by click event
     */
    private OnTouchListener mPreventMoveOnTouchListener = new OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            return motionEvent.getAction() == MotionEvent.ACTION_MOVE;
        }
    };
    /**
     * We catch move event on melody item and start drag event
     */
    private View mDraggingAlarmItemView;
    private OnLongClickListener mLongItemClickListener = new OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            setRecycleViewVisibility(VISIBLE);
            inactiveRecycleBin();
            mDraggingAlarmItemView = view;
            DragShadowBuilder shadowBuilder = new DragShadowBuilder(mDraggingAlarmItemView);
            ClipData data = ClipData.newPlainText(ConstantUtils.EMPTY_STRING, ConstantUtils.EMPTY_STRING);
            //noinspection deprecation
            mDraggingAlarmItemView.startDrag(data, shadowBuilder, view, FLAG_DRAG);
            mDraggingAlarmItemView.setVisibility(View.INVISIBLE);

            return true;
        }
    };

    @Override
    public void navigateToEditAlarmActivity(int alarmId) {
        Intent intent = new Intent(getContext(), AddAlarmActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        intent.putExtra(AddAlarmActivity.EXTRA_ALARM_ID, alarmId);
        getContext().startActivity(intent);
    }

    private void deleteAlarm(AlarmItemViewHolder holder) {
        final AlarmData deletedAlarm = holder.mAlarmData;
        mMainActivity.showProgressDialog(mMainActivity.getString(R.string.progress_dialog_msg_save));
        mPresenter.deleteAlarm(deletedAlarm, new DBManager.OnSaveDataResultListener() {
            @Override
            public void onSuccess() {
                mMainActivity.dismissProgressDialog();
                mPresenter.cancelAlarmFromAlarmManager(deletedAlarm.getId());
            }

            @Override
            public void onError(int i) {
                mMainActivity.dismissProgressDialog();
                CommonUtils.showHDDErrorDialog(mMainActivity, i);
            }
        });
    }

    private void setRecycleViewVisibility(int visibility) {
        if (mRecycleBinContainer == null) {
            return;
        }
        mRecycleBinContainer.setVisibility(visibility);
    }

    private OnDragListener mOnItemDragListener = new OnDragListener() {
        @Override
        public boolean onDrag(View targetContainer, final DragEvent dragEvent) {
            switch (dragEvent.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    break;
                case DragEvent.ACTION_DRAG_ENTERED:
                    if (!(targetContainer instanceof ImageView)) {
                        return false;
                    }
                    activeRecycleBin();
                    break;
                case DragEvent.ACTION_DRAG_EXITED:
                    inactiveRecycleBin();
                    break;
                case DragEvent.ACTION_DROP:
                    if (mIsRecycleBinActive) {
                        deleteAlarm(((AlarmItemViewHolder) mDraggingAlarmItemView.getTag()));
                    }
                    mDraggingAlarmItemView.setVisibility(VISIBLE);
                    break;
                case DragEvent.ACTION_DRAG_ENDED:
                    mDraggingAlarmItemView.post(new Runnable() {
                        @Override
                        public void run() {
                            mDraggingAlarmItemView.setVisibility(VISIBLE);
                        }
                    });
                    setRecycleViewVisibility(GONE);
                    break;
                default:
                    return false;
            }
            return true;
        }
    };

    /**
     * Active the recycle bin, enable drop item
     */
    private void activeRecycleBin() {
        if (mRecycleBinImg != null) {
            mRecycleBinImg.setBackgroundResource(R.drawable.ic_remove_red);
            mIsRecycleBinActive = true;
        }
    }

    /**
     * Inactive the recycle bin
     */
    private void inactiveRecycleBin() {
        if (mRecycleBinImg != null) {
            mRecycleBinImg.setBackgroundResource(R.drawable.ic_remove);
            mIsRecycleBinActive = false;

        }
    }

    public void setRecycleView(RelativeLayout recycleBinContainer, ImageView recycleBinImg) {
        mRecycleBinContainer = recycleBinContainer;
        mRecycleBinImg = recycleBinImg;
        if (mRecycleBinImg != null) {
            mRecycleBinImg.setOnLongClickListener(mLongItemClickListener);
            // to catch enter event
            mRecycleBinImg.setOnDragListener(mOnItemDragListener);
        }
    }

    @Override
    public void scrollUp() {
        smoothScrollToPosition(0);
    }

    @Override
    public void setActivity(MainActivity activity) {
        mMainActivity = activity;
    }

    public void onDestroy() {
        mPresenter.onDestroyView();
    }

    @Override
    public AlarmItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        AlarmItemViewBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.itemview_alarm, parent, false);
        AlarmItemViewHolder holder = new AlarmItemViewHolder(binding);
        binding.cardView.setTag(holder);
        binding.cardView.setOnClickListener(mOnItemClickListener);
        binding.cardView.setOnLongClickListener(mLongItemClickListener);
        binding.cardView.setOnDragListener(mOnItemDragListener);
        binding.switchEnable.setTag(holder);
        binding.switchEnable.setOnClickListener(mSwitchClickListener);
        binding.switchEnable.setOnTouchListener(mPreventMoveOnTouchListener);
        return holder;
    }

    @Override
    public void onBindViewHolder(AlarmItemViewHolder viewHolder, AlarmData itemData) {
        viewHolder.setAlarmData(itemData);

    }

    public static class AlarmItemViewHolder extends ViewHolder {
        private AlarmItemViewBinding mBinding;
        private AlarmData mAlarmData;

        public AlarmItemViewHolder(AlarmItemViewBinding binding) {
            super(binding.getRoot());
            mBinding = binding;
        }

        public void setAlarmData(AlarmData alarmData) {
            mAlarmData = alarmData;
            if (mAlarmData != null) {
                mBinding.dayListView.setDays(alarmData.getDays());
                mBinding.txtLabel.setText(alarmData.getLabel());
                mBinding.txtTime.setText(CommonUtils.formatTime(mAlarmData));
                mBinding.txtAmpm.setText(CommonUtils.formatAMPM(mBinding.txtAmpm.getContext(), mAlarmData));
                mBinding.switchEnable.setChecked(mAlarmData.isEnabled());
                if (alarmData.isRepeatEnabled()) {
                    mBinding.itemAlarmRepeatWeekly.setVisibility(View.VISIBLE);
                    boolean isRepeatAllDay = true;
                    for (boolean isSelectedDay : alarmData.getDays()) {
                        if (!isSelectedDay) {
                            isRepeatAllDay = false;
                            break;
                        }
                    }
                    if (isRepeatAllDay) {
                        mBinding.itemAlarmRepeatWeekly.setText(mBinding.itemAlarmRepeatWeekly.getContext().getString(R.string.every_day));
                        mBinding.dayListView.setVisibility(View.GONE);
                    } else {
                        mBinding.itemAlarmRepeatWeekly.setText(mBinding.itemAlarmRepeatWeekly.getContext().getString(R.string.every));
                        mBinding.dayListView.setVisibility(View.VISIBLE);
                    }
                } else {
                    mBinding.itemAlarmRepeatWeekly.setVisibility(View.GONE);
                    mBinding.dayListView.setVisibility(View.VISIBLE);
                }
            }
        }
    }

}
